home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue68 / Alfresco / AAPasTok.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-03-04  |  12.4 KB  |  440 lines

  1. unit AAPasTok;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils,
  7.   AAChrStm,
  8.   AAHshLnP;
  9.  
  10. type
  11.   TaaPascalToken = ( {types of Pascal tokens...}
  12.     ptInvalidToken,  {..some kind of error}
  13.     ptEndOfFile,     {..end of file}
  14.     ptKeyword,       {..keyword, eg, if, while, do, ...}
  15.     ptIdentifier,    {..identifier}
  16.     ptString,        {..string or character constant}
  17.     ptHexNumber,     {..number in hex, starts with $}
  18.     ptNumber,        {..sequence of digits, maybe with radix point}
  19.     ptComment,       {..comment, any type}
  20.     ptComma,         {..comma: ,}
  21.     ptSemicolon,     {..semicolon: ;}
  22.     ptColon,         {..colon: :}
  23.     ptPeriod,        {..period: .}
  24.     ptRange,         {..range: ..}
  25.     ptEquals,        {..equals char: =}
  26.     ptNotEquals,     {..not equals: <>}
  27.     ptLess,          {..less than: <}
  28.     ptLessEqual,     {..less than or equal: <=}
  29.     ptGreater,       {..greater than: >}
  30.     ptGreaterEqual,  {..greater than or equal: >=}
  31.     ptAssign,        {..assignment: :=}
  32.     ptOpenParen,     {..open parenthesis: (}
  33.     ptCloseParen,    {..close parenthesis: )}
  34.     ptOpenBracket,   {..open bracket: [}
  35.     ptCloseBracket,  {..close bracket: ]}
  36.     ptCaret,         {..caret: ^}
  37.     ptHash,          {..hash: #}
  38.     ptAddress,       {..ampersand: @}
  39.     ptPlus,          {..addition: +}
  40.     ptMinus,         {..subtraction: -}
  41.     ptMultiply,      {..multiplication: *}
  42.     ptDivide);       {..division: /}
  43.  
  44. type
  45.   TaaPascalParser = class
  46.     private
  47.       FInStrm   : TaaInCharStream;
  48.       FKeywords : TaaHashTableLinear;
  49.     protected
  50.       procedure ppInitKeywords;
  51.     public
  52.       constructor Create(aInStm : TaaInCharStream);
  53.       destructor Destroy; override;
  54.  
  55.       procedure GetToken(var aTokenType : TaaPascalToken;
  56.                          var aToken     : string);
  57.   end;
  58.  
  59.  
  60. procedure AAGetToken(aInStm     : TaaInCharStream;
  61.                  var aTokenType : TaaPascalToken;
  62.                  var aToken     : string);
  63.  
  64. implementation
  65.  
  66. const
  67.   KeywordCount = 106;
  68.   KeywordList : array [0..pred(KeywordCount)] of string = (
  69.     {reserved words}
  70.     'AND', 'ARRAY', 'AS', 'ASM', 'BEGIN', 'CASE', 'CLASS', 'CONST',
  71.     'CONSTRUCTOR', 'DESTRUCTOR', 'DISPINTERFACE', 'DIV', 'DO',
  72.     'DOWNTO', 'ELSE', 'END', 'EXCEPT', 'EXPORTS', 'FILE',
  73.     'FINALIZATION', 'FINALLY', 'FOR', 'FUNCTION', 'GOTO', 'IF',
  74.     'IMPLEMENTATION', 'IN', 'INHERITED', 'INITIALIZATION', 'INLINE',
  75.     'INTERFACE', 'IS', 'LABEL', 'LIBRARY', 'MOD', 'NIL', 'NOT',
  76.     'OBJECT', 'OF', 'OR', 'OUT', 'PACKED', 'PROCEDURE', 'PROGRAM',
  77.     'PROPERTY', 'RAISE', 'RECORD', 'REPEAT', 'RESOURCESTRING', 'SET',
  78.     'SHL', 'SHR', 'STRING', 'THEN', 'THREADVAR', 'TO', 'TRY', 'TYPE',
  79.     'UNIT', 'UNTIL', 'USES', 'VAR', 'WHILE', 'WITH', 'XOR',
  80.     {directives}
  81.     'ABSOLUTE', 'ABSTRACT', 'ASSEMBLER', 'AUTOMATED', 'CDECL',
  82.     'CONTAINS', 'DEFAULT', 'DISPID', 'DYNAMIC', 'EXPORT', 'EXTERNAL',
  83.     'FAR', 'FORWARD', 'IMPLEMENTS', 'INDEX', 'MESSAGE', 'NAME',
  84.     'NEAR', 'NODEFAULT', 'OVERLOAD', 'OVERRIDE', 'PACKAGE', 'PASCAL',
  85.     'PRIVATE', 'PROTECTED', 'PUBLIC', 'PUBLISHED', 'READ', 'READONLY',
  86.     'REGISTER', 'REINTRODUCE', 'REQUIRES', 'RESIDENT', 'SAFECALL',
  87.     'STDCALL', 'STORED', 'VIRTUAL', 'WRITE', 'WRITEONLY',
  88.     {others}
  89.     'AT', 'ON'
  90.     );
  91.  
  92. {===TaaPascalParser==================================================}
  93. constructor TaaPascalParser.Create(aInStm : TaaInCharStream);
  94. begin
  95.   {create the ancestor}
  96.   inherited Create;
  97.  
  98.   {save the stream}
  99.   FInStrm := aInstm;
  100.  
  101.   {create the keywords list}
  102.   FKeywords := TaaHashTableLinear.Create(199, AAELFHash);
  103.   ppInitKeywords;
  104.  
  105. end;
  106. {--------}
  107. destructor TaaPascalParser.Destroy;
  108. begin
  109.   {destroy the keywords list}
  110.   FKeywords.Free;
  111.   {destroy the ancestor}
  112.   inherited Destroy;
  113. end;
  114. {--------}
  115. procedure TaaPascalParser.GetToken(var aTokenType : TaaPascalToken;
  116.                                    var aToken     : string);
  117. var
  118.   DummyObj : pointer;
  119. begin
  120.   AAGetToken(FInStrm, aTokenType, aToken);
  121.   if (aTokenType = ptIdentifier) then
  122.     if FKeywords.Find(UpperCase(aToken), DummyObj) then
  123.       aTokenType := ptKeyword;
  124. end;
  125. {--------}
  126. procedure TaaPascalParser.ppInitKeywords;
  127. var
  128.   i : integer;
  129. begin
  130.   Assert(FKeywords <> nil,
  131.          'ppInitKeywords cannot be called with nil hash table');
  132.   for i := 0 to pred(KeywordCount) do
  133.     FKeywords.Insert(KeyWordList[i], nil);
  134. end;
  135. {====================================================================}
  136.  
  137.  
  138. {===Helper routines==================================================}
  139. procedure ReadNumber(aInStm : TaaInCharStream;
  140.                  var aToken : string);
  141. var
  142.   Ch : char;
  143.   State : (BeforeDecPt, GotDecPt, AfterDecPt, Finished);
  144. begin
  145.   State := BeforeDecPt;
  146.   while (State <> Finished) do begin
  147.     Ch := aInStm.GetChar;
  148.     if (Ch = #0) then begin
  149.       State := Finished;
  150.       aInStm.PutBackChar(Ch);
  151.     end
  152.     else begin
  153.       case State of
  154.         BeforeDecPt :
  155.           begin
  156.             if (Ch = '.') then begin
  157.               State := GotDecPt;
  158.             end
  159.             else if (Ch < '0') or (Ch > '9') then begin
  160.               State := Finished;
  161.               aInStm.PutBackChar(Ch);
  162.             end
  163.             else
  164.               aToken := aToken + Ch;
  165.           end;
  166.         GotDecPt :
  167.           begin
  168.             if (Ch = '.') then begin
  169.               aInStm.PutBackChar(Ch);
  170.               aInStm.PutBackChar(Ch);
  171.               State := Finished;
  172.             end
  173.             else begin
  174.               aToken := aToken + '.';
  175.               aToken := aToken + Ch;
  176.               State := AfterDecPt;
  177.             end;
  178.           end;
  179.         AfterDecPt :
  180.           begin
  181.             if (Ch < '0') or (Ch > '9') then begin
  182.               State := Finished;
  183.               aInStm.PutBackChar(Ch);
  184.             end
  185.             else
  186.               aToken := aToken + Ch;
  187.           end;
  188.       end;
  189.     end;
  190.   end;
  191. end;
  192. {--------}
  193. procedure ReadHexNumber(aInStm : TaaInCharStream;
  194.                     var aToken : string);
  195. var
  196.   Ch : char;
  197.   State : (NormalScan, Finished);
  198. begin
  199.   State := NormalScan;
  200.   while (State <> Finished) do begin
  201.     Ch := aInStm.GetChar;
  202.     if (Ch = #0) then begin
  203.       State := Finished;
  204.       aInStm.PutBackChar(Ch);
  205.     end
  206.     else begin
  207.       case State of
  208.         NormalScan :
  209.           begin
  210.             if not (Ch in ['A'..'F', 'a'..'f', '0'..'9']) then begin
  211.               State := Finished;
  212.               aInStm.PutBackChar(Ch);
  213.             end
  214.             else
  215.               aToken := aToken + Ch;
  216.           end;
  217.       end;
  218.     end;
  219.   end;
  220. end;
  221. {--------}
  222. procedure ReadIdentifier(aInStm : TaaInCharStream;
  223.                      var aToken : string);
  224. var
  225.   Ch : char;
  226. begin
  227.   Ch := aInStm.GetChar;
  228.   while Ch in ['A'..'Z', 'a'..'z', '0'..'9', '_'] do begin
  229.     aToken := aToken + Ch;
  230.     Ch := aInStm.GetChar;
  231.   end;
  232.   aInStm.PutBackchar(Ch);
  233. end;
  234. {--------}
  235. procedure ReadString(aInStm : TaaInCharStream;
  236.                  var aToken : string);
  237. var
  238.   Ch : char;
  239. begin
  240.   Ch := aInStm.GetChar;
  241.   while (Ch <> '''') and (Ch <> #0) do begin
  242.     aToken := aToken + Ch;
  243.     Ch := aInStm.GetChar;
  244.   end;
  245.   if (Ch = '''') then
  246.     aToken := aToken + Ch
  247.   else
  248.     aInStm.PutBackchar(Ch);
  249. end;
  250. {--------}
  251. procedure ReadBraceComment(aInStm : TaaInCharStream;
  252.                        var aToken : string);
  253. var
  254.   Ch : char;
  255. begin
  256.   Ch := aInStm.GetChar;
  257.   while (Ch <> '}') and (Ch <> #0) do begin
  258.     aToken := aToken + Ch;
  259.     Ch := aInStm.GetChar;
  260.   end;
  261.   if (Ch = '}') then
  262.     aToken := aToken + Ch
  263.   else
  264.     aInStm.PutBackchar(Ch);
  265. end;
  266. {--------}
  267. procedure ReadSlashComment(aInStm : TaaInCharStream;
  268.                        var aToken : string);
  269. var
  270.   Ch : char;
  271. begin
  272.   Ch := aInStm.GetChar;
  273.   while (Ch <> #10) and (Ch <> #0) do begin
  274.     aToken := aToken + Ch;
  275.     Ch := aInStm.GetChar;
  276.   end;
  277.   aInStm.PutBackchar(Ch);
  278. end;
  279. {--------}
  280. procedure ReadParenComment(aInStm : TaaInCharStream;
  281.                        var aToken : string);
  282. var
  283.   Ch : char;
  284.   State : (NormalScan, GotStar, Finished);
  285. begin
  286.   State := NormalScan;
  287.   while (State <> Finished) do begin
  288.     Ch := aInStm.GetChar;
  289.     if (Ch = #0) then begin
  290.       State := Finished;
  291.       aInStm.PutBackChar(Ch);
  292.     end
  293.     else begin
  294.       aToken := aToken + Ch;
  295.       case State of
  296.         NormalScan :
  297.           if (Ch = '*') then
  298.             State := GotStar;
  299.         GotStar :
  300.           if (Ch = ')') then
  301.             State := Finished
  302.           else
  303.             State := NormalScan;
  304.       end;
  305.     end;
  306.   end;
  307. end;
  308. {====================================================================}
  309.  
  310.  
  311. {===Interface routine================================================}
  312. procedure AAGetToken(aInStm     : TaaInCharStream;
  313.                  var aTokenType : TaaPascalToken;
  314.                  var aToken     : string);
  315. var
  316.   Ch : char;
  317. begin
  318.   {assume we have an invalid token}
  319.   aTokenType := ptInvalidToken;
  320.   aToken := '';
  321.   {ignore any whitespace prior to the token}
  322.   Ch := aInStm.GetChar;
  323.   while (Ch <> #0) and (Ch <= ' ') do
  324.     Ch := aInStm.GetChar;
  325.   {if we've reached end-of-file, exit returning that token type}
  326.   if (Ch = #0) then begin
  327.     aTokenType := ptEndOfFile;
  328.     Exit;
  329.   end;
  330.   {parse the token based on the current character}
  331.   case Ch of
  332.     '#' : aTokenType := ptHash;
  333.     '$' : begin
  334.             aTokenType := ptNumber;
  335.             aToken := Ch;
  336.             ReadHexNumber(aInStm, aToken);
  337.           end;
  338.     '''': begin
  339.             aTokenType := ptString;
  340.             aToken := '''';
  341.             ReadString(aInStm, aToken);
  342.           end;
  343.     '(' : begin
  344.             Ch := aInStm.GetChar;
  345.             if (Ch <> '*') then begin
  346.               aInStm.PutBackChar(Ch);
  347.               aTokenType := ptOpenParen;
  348.             end
  349.             else begin
  350.               aTokenType := ptComment;
  351.               aToken := '(*';
  352.               ReadParenComment(aInStm, aToken);
  353.             end;
  354.           end;  
  355.     ')' : aTokenType := ptCloseParen;
  356.     '*' : aTokenType := ptMultiply;
  357.     '+' : aTokenType := ptPlus;
  358.     ',' : aTokenType := ptComma;
  359.     '-' : aTokenType := ptMinus;
  360.     '.' : begin
  361.             Ch := aInStm.GetChar;
  362.             if (Ch = '.') then
  363.               aTokenType := ptRange
  364.             else begin
  365.               aInStm.PutBackChar(Ch);
  366.               aTokenType := ptPeriod;
  367.             end;
  368.           end;
  369.     '/' : begin
  370.             Ch := aInStm.GetChar;
  371.             if (Ch <> '/') then begin
  372.               aInStm.PutBackChar(Ch);
  373.               aTokenType := ptDivide;
  374.             end
  375.             else begin
  376.               aTokenType := ptComment;
  377.               aToken := '//';
  378.               ReadSlashComment(aInStm, aToken);
  379.             end;
  380.           end;
  381.     '0'..'9' :
  382.           begin
  383.             aTokenType := ptNumber;
  384.             aToken := Ch;
  385.             ReadNumber(aInStm, aToken);
  386.           end;
  387.     ':' : begin
  388.             Ch := aInStm.GetChar;
  389.             if (Ch = '=') then
  390.               aTokenType := ptAssign
  391.             else begin
  392.               aInStm.PutBackChar(Ch);
  393.               aTokenType := ptColon;
  394.             end;
  395.           end;
  396.     ';' : aTokenType := ptSemicolon;
  397.     '<' : begin
  398.             Ch := aInStm.GetChar;
  399.             if (Ch = '=') then
  400.               aTokenType := ptLessEqual
  401.             else if (Ch = '>') then
  402.               aTokenType := ptNotEquals
  403.             else begin
  404.               aInStm.PutBackChar(Ch);
  405.               aTokenType := ptLess;
  406.             end;
  407.           end;
  408.     '=' : aTokenType := ptEquals;
  409.     '>' : begin
  410.             Ch := aInStm.GetChar;
  411.             if (Ch = '=') then
  412.               aTokenType := ptGreaterEqual
  413.             else begin
  414.               aInStm.PutBackChar(Ch);
  415.               aTokenType := ptLess;
  416.             end;
  417.           end;
  418.     '@' : aTokenType := ptAddress;
  419.     'A'..'Z', 'a'..'z', '_' :
  420.           begin
  421.             aTokenType := ptIdentifier;
  422.             aToken := Ch;
  423.             ReadIdentifier(aInStm, aToken);
  424.           end;
  425.     '[' : aTokenType := ptOpenBracket;
  426.     ']' : aTokenType := ptCloseBracket;
  427.     '^' : aTokenType := ptCaret;
  428.     '{' : begin
  429.             aTokenType := ptComment;
  430.             aToken := '{';
  431.             ReadBraceComment(aInStm, aToken);
  432.           end;
  433.   end;
  434.   Assert(aTokenType <> ptInvalidToken,
  435.          'Managed to find an invalid token.');
  436. end;
  437. {====================================================================}
  438.  
  439. end.
  440.